/*
Copyright (C) 2009-2010 Xanadu Development Team

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2
of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "../../Connection/PacketHandler.h"
#include "../net/world/Party.h"
#include "../tools/MySQLM.h"
#include "Pet.h"
#include "Map.h"
#include "PlayerInventory.h"
#include "Inventory.h"
#include "PlayerKeys.h"
#include "PlayerSkills.h"
#include "Skill.h"
#include "Equip.h"
#include "Item.h"
#include "Key.h"
#include "Player.h"
#include "Players.h"
#include "PlayerQuests.h"
#include "Channel.h"
#include "Channels.h"
#include "../net/world/World.h"
#include "../net/world/Worlds.h"
#include "Quest.h"
#include "../net/world/Guild.h"
using namespace mysqlpp;

void Player::save() {
	saveChar();
	saveEquips();
	saveItems();
	savePets();
	saveQuests();
	saveSkills();
	saveVars();
}

void Player::saveChar() {
	Connection::thread_start();
	Connection* conn = MySQL::getInstance()->getPool()->grab();
	Query query = conn->query();
	query << "UPDATE characters SET level='" << (int)level << "', job='" << (int)job << "', str='" << (int)str << "', dex='" << (int)dex << "', intt='" << (int)intt << "', luk='" << (int)luk << "', hp='" << hp << "', mhp='" << bmhp << "', mp='" << mp << "', mmp='" << bmmp << "', ap='" << (int)ap << "', sp='" << (int)sp << "', exp='" << (int)exp << "', fame=" << (int)fame << ", map='" << map->getID() << "', pos='" << (int)map->getClosestSpawnPos(pos) << "', gender='" << (int)gender << "', face='" << (int)face << "', hair='" << (int)hair << "', mesos='" << mesos << "', hpap='" << (int)hpap << "', mpap='" << (int)mpap << "', party='" << (int)((party == 0) ? 0 : party->getID()) << "', guild='" << (int)((guild == 0) ? 0 : guild->getID()) << "', guildrank='" << (int)guildRank << "' WHERE ID=" << id;
	query.execute();
	MySQL::getInstance()->getPool()->release(conn);
	Connection::thread_end();
}

void Player::saveNX() {
	Connection::thread_start();
	Connection* conn = MySQL::getInstance()->getPool()->grab();
	Query query = conn->query();
	query << "UPDATE accounts SET Paypalnx='" << Paypalnx << "', MaplePoints='" << MaplePoints << "', Cardnx='" << Cardnx << "' WHERE ID=" << getUserId();
	query.execute();
	MySQL::getInstance()->getPool()->release(conn);
	Connection::thread_end();
}

void Player::saveEquips() {
	Connection::thread_start();
	Connection* conn = MySQL::getInstance()->getPool()->grab();
	Query query = conn->query();
	query << "DELETE FROM equips WHERE charid=" << id;
	query.execute();
	for(int i = EQUIPPED; i <= EQUIP; i++) {
		bool firstrun = true;
		hash_map <int, Item*>* items = inv->getInventory(i)->getItems();
		for(hash_map<int, Item*>::iterator iter = items->begin(); iter!=items->end(); iter++) {
			Item* item = iter->second;
			if(IS_EQUIP(item->getID())) {
				Equip* equip = (Equip*)item;
				if(!firstrun)
					query << ",";
				else{
					query << "INSERT INTO equips VALUES";
					firstrun = false;
				}
				query << "(" << equip->getID() << "," << id << "," << (int)equip->getSlot() << "," << (int)equip->getSlots() << "," << (int)equip->getScrolls() << "," << (int)equip->getStr() << "," << (int)equip->getDex() << "," << (int)equip->getInt() << "," << (int)equip->getLuk() << "," << (int)equip->getHp() << "," << (int)equip->getMp() << "," << (int)equip->getWAtk() << "," << (int)equip->getMAtk() << "," << (int)equip->getWDef() << "," << (int)equip->getMDef() << "," << (int)equip->getAcc() << "," << (int)equip->getAvo() << "," << (int)equip->getHand() << "," << (int)equip->getSpeed() << "," << (int)equip->getJump() << ",'" << equip->getOwner() << "'," << (equip->getLocked() ? 1 : 0) << "," << (int)equip->getHammerSlots() << "," << (equip->getCash() ? 1 : 0) << ")";
			}
		}
		if(!firstrun)
			query.execute();
	}
	MySQL::getInstance()->getPool()->release(conn);
	Connection::thread_end();
}

void Player::saveItems() {
	Connection::thread_start();
	Connection* conn = MySQL::getInstance()->getPool()->grab();
	Query query = conn->query();
	query << "DELETE FROM items WHERE charid=" << id;
	query.execute();
	for(int i = USE; i <= CASH; i++) {
		bool firstrun = true;
		hash_map <int, Item*>* items = inv->getInventory(i)->getItems();
		for(hash_map<int, Item*>::iterator iter = items->begin(); iter!=items->end(); iter++) {
			Item* item = iter->second;
			if(!IS_PET(item->getID())) {
				if(!firstrun)
					query << ",";
				else{
					query << "INSERT INTO items VALUES";
					firstrun = false;
				}
				query << "(" << item->getID() << "," << id << "," << (int)item->getType() << "," << (int)item->getSlot() << "," << (int)item->getAmount() << ")";
			}
		}
		if(!firstrun)
			query.execute();
	}
	MySQL::getInstance()->getPool()->release(conn);
	Connection::thread_end();
}

void Player::savePets() {
	Connection::thread_start();
	Connection* conn = MySQL::getInstance()->getPool()->grab();
	Query query = conn->query();
	query << "DELETE FROM pets WHERE charid=" << id;
	query.execute();
	bool firstrun = true;
	hash_map <int, Item*>* items = inv->getInventory(CASH)->getItems();
	for(hash_map<int, Item*>::iterator iter = items->begin(); iter!=items->end(); iter++) {
		Item* item = iter->second;
		if(IS_PET(item->getID())) {
			if(!firstrun)
				query << ",";
			else{
				query << "INSERT INTO pets VALUES";
				firstrun = false;
			}
			Pet* pet = (Pet*)item;
			char number[50];
			sprintf_s(number, 50, "%I64d", pet->getTime());
			query << "(" << pet->getItemID() << "," << id << "," << (int)pet->getSlot() << "," << (int)pet->getPetSlot() << ",'" << pet->getName() << "'," << (int)pet->getLevel() << "," << (int)pet->getCloseness() << "," << (int)pet->getFullness() << "," << number << ")";
		}
	}
	if(!firstrun)
		query.execute();
	MySQL::getInstance()->getPool()->release(conn);
	Connection::thread_end();
}

void Player::saveKeys() {
	Connection::thread_start();
	Connection* conn = MySQL::getInstance()->getPool()->grab();
	Query query = conn->query();
	query << "DELETE FROM keymap WHERE charid=" << id;
	query.execute();
	bool firstrun = true;
	for(int i = 0; i < 90; i++){
		Key* key = keys->getKey(i);
		if(key != 0) {
			if (!firstrun)
				query << ",";
			else {
				query << "INSERT INTO keymap VALUES";
				firstrun = false;
			}
			query << "(" << id << "," << i << "," << (int)key->getType() << "," << key->getAction() << ")";
		}
	}
	if(!firstrun)
		query.exec();
	MySQL::getInstance()->getPool()->release(conn);
	Connection::thread_end();
}

void Player::saveSkills() {
	Connection::thread_start();
	Connection* conn = MySQL::getInstance()->getPool()->grab();
	Query query = conn->query();
	query << "DELETE FROM skills WHERE charid=" << id;
	query.execute();
	bool firstrun = true;
	hash_map <int, Skill*>* skillsd = skills->getSkillsInfo();
	for(hash_map<int, Skill*>::iterator iter = skillsd->begin(); iter!=skillsd->end(); iter++) {
		if (firstrun) {
			query << "REPLACE INTO skills VALUES (";
			firstrun = false;
		}
		else {
			query << ",(";
		}
		query << id << "," << iter->first << "," << (short) iter->second->getLevel() << "," << (short) iter->second->getMasterLevel() << ")";
	}
	if (!firstrun)
		query.exec();
	MySQL::getInstance()->getPool()->release(conn);
	Connection::thread_end();
}

void Player::saveVars() {
	Connection::thread_start();
	Connection* conn = MySQL::getInstance()->getPool()->grab();
	Query query = conn->query();
	query << "DELETE FROM vars WHERE charid=" << id;
	query.execute();
	bool firstrun = true;
	for(hash_map<string, int>::iterator iter = vars.begin(); iter != vars.end(); iter++) {
		if(!firstrun)
			query << ",";
		else{
			query << "INSERT INTO vars VALUES";
			firstrun = false;
		}
		query << "(" << id << ", '" << iter->first << "', '" << iter->second << "')";
	}
	if (!firstrun)
		query.execute();
	MySQL::getInstance()->getPool()->release(conn);
	Connection::thread_end();
}

void Player::saveQuests() {
	Connection::thread_start();
	Connection* conn = MySQL::getInstance()->getPool()->grab();
	Query query = conn->query();
	query << "DELETE FROM quests WHERE charid=" << id;
	query.execute();
	bool firstrun = true;
	hash_map <int, Quest*>* cquests = getQuests()->getCompletedQuestsInfo();
	for(hash_map<int, Quest*>::iterator iter = cquests->begin(); iter!=cquests->end(); iter++) {
		if(!firstrun)
			query << ",";
		else{
			query << "INSERT INTO quests (charid, questid, iscomplete) VALUES";
			firstrun = false;
		}
		query << "(" << id << "," << iter->second->getID() << ", 1" << ")";
	}
	if (!firstrun)
		query.execute();
	firstrun = 1;
	hash_map <int, Quest*>* pquests = getQuests()->getQuestsInProgressInfo();
	for(hash_map<int, Quest*>::iterator iter = pquests->begin(); iter!=pquests->end(); iter++) {
		if(!firstrun)
			query << ",";
		else{
		query << "INSERT INTO quests (charid, questid, iscomplete, killedmob, amount) VALUES";
		firstrun = false;
		}
		if (iter->second->getKilledmobs()->size() == 0) {
			query << "(" << id << "," << iter->second->getID() << ", 0, 0, 0)";
		}
		for(int i=0; i < (int)iter->second->getKilledmobs()->size(); i++){
			query << "(" << id << "," << iter->second->getID() << ", 0," << iter->second->getKilledmobs()->at(i).id << "," << iter->second->getKilledmobs()->at(i).count << ")";
		}
	}
	if (!firstrun)
		query.execute();
	MySQL::getInstance()->getPool()->release(conn);
	Connection::thread_end();
}